#include <iostream>
#include <vector>
#include <gtkmm.h>
#include "gui.h"

using namespace std;
using namespace Gtk;

VentanaPrincipal::VentanaPrincipal()
{
	// Configurar ventana.
	set_title("Microlibre");
	set_border_width(12);

	// Armar layout.
	VBox *vbox = manage(new VBox());
	vbox->set_spacing(12);
	add(*vbox);

	// TODO(pdallago): Separar esto en una funcion aparte.
	// Crear barra de herramientas.
	Toolbar *toolbar = manage(new Toolbar());
	toolbar->set_toolbar_style(TOOLBAR_BOTH);
	vbox->pack_start(*toolbar, PACK_SHRINK);
	ToolButton *toolbar_button = manage(new ToolButton(Stock::EXECUTE));
	toolbar_button->set_label("Ejecutar");
	toolbar_button->set_border_width(3);
	toolbar->append(*toolbar_button, sigc::mem_fun(*this, &VentanaPrincipal::accionProxima));
	toolbar_button = manage(new ToolButton(Stock::STOP));
	toolbar_button->set_label("Parar");
	toolbar_button->set_border_width(3);
	toolbar->append(*toolbar_button, sigc::mem_fun(*this, &VentanaPrincipal::accionEjecutar));
	toolbar_button = manage(new ToolButton(Stock::MEDIA_NEXT));
	toolbar_button->set_label("Avanzar un paso");
	toolbar_button->set_border_width(3);
	toolbar->append(*toolbar_button, sigc::mem_fun(*this, &VentanaPrincipal::accionParar));
	toolbar_button = manage(new ToolButton(Stock::REFRESH));
	toolbar_button->set_label("Resetear");
	toolbar_button->set_border_width(3);
	toolbar->append(*toolbar_button, sigc::mem_fun(*this, &VentanaPrincipal::accionResetear));

	// Crear frame para los registros.
	HBox *hbox = manage(new HBox());
	hbox->set_spacing(12);
	vbox->pack_start(*hbox);
	Alignment* alignment = manage(new Alignment(ALIGN_LEFT, ALIGN_TOP, 0, 0));
	hbox->pack_start(*alignment, PACK_SHRINK);
	Frame *frame = manage(new Frame("Registros"));
	alignment->add(*frame);
	alignment = manage(new Alignment());
	alignment->set_padding(12, 12, 12, 12);
	frame->add(*alignment);
	Table *table = manage(new Table(6, 4));
	table->set_col_spacing(0, 6);
	table->set_col_spacing(1, 12);
	table->set_col_spacing(2, 6);
	table->set_row_spacings(24);
	alignment->add(*table);

	// Agregar cajas de texto para los registros.
	agregarRegistros(table);

	// TODO(pdallago): Separar esto en una funcion aparte.
	// Configurar la vista del codigo.
	ScrolledWindow *scrolled_window = manage(new ScrolledWindow());
	scrolled_window->set_policy(POLICY_NEVER, POLICY_AUTOMATIC);
	scrolled_window->set_shadow_type(SHADOW_IN);
	hbox->pack_start(*scrolled_window);
	codigo_ = manage(new ListViewText(3, false, SELECTION_NONE));
	scrolled_window->add(*codigo_);
	codigo_->set_enable_search(false);
	codigo_->set_column_title(0, "Direccion");
	codigo_->set_column_title(1, "Opcode");
	codigo_->set_column_title(2, "Instruccion");
	for (int i = 0; i < 10; i++) {
		codigo_->append_text("0100:0000h");
		codigo_->set_text(i, 1, "F9 A2");
		codigo_->set_text(i, 2, "MOV AX, AX");
	}

	// Mostrar ventana con todos los widgets.
	show_all_children();
}

void VentanaPrincipal::agregarRegistros(Table *table)
{
	Label *label;
	Alignment *alignment;
	vector<s_widget_info> datos;
	datos.push_back((s_widget_info) {"A", 0, 1, 0, 1, registro_a_, 2});
	datos.push_back((s_widget_info) {"PSW", 2, 3, 0, 1, registro_psw_, 2});
	datos.push_back((s_widget_info) {"B", 0, 1, 1, 2, registro_b_, 2});
	datos.push_back((s_widget_info) {"C", 2, 3, 1, 2, registro_c_, 2});
	datos.push_back((s_widget_info) {"D", 0, 1, 2, 3, registro_d_, 2});
	datos.push_back((s_widget_info) {"E", 2, 3, 2, 3, registro_e_, 2});
	datos.push_back((s_widget_info) {"H", 0, 1, 3, 4, registro_h_, 2});
	datos.push_back((s_widget_info) {"L", 2, 3, 3, 4, registro_l_, 2});
	datos.push_back((s_widget_info) {"M", 0, 1, 4, 5, registro_m_, 2});
	datos.push_back((s_widget_info) {"SP", 2, 3, 4, 5, registro_sp_, 4});
	datos.push_back((s_widget_info) {"PC", 0, 1, 5, 6, registro_pc_, 4});

	for (int i = 0; i < datos.size(); i++) {
		label = manage(new Label(datos[i].name));
		alignment = manage(new Alignment(ALIGN_RIGHT, ALIGN_CENTER, 0, 0));
		alignment->add(*label);
		table->attach(*alignment, datos[i].left, datos[i].right, datos[i].top, datos[i].bottom);
		datos[i].entry = manage(new Entry());
		(datos[i].entry)->set_width_chars(datos[i].width);
		(datos[i].entry)->set_max_length(datos[i].width);
		alignment = manage(new Alignment(ALIGN_LEFT, ALIGN_CENTER, 0, 0));
		alignment->add(*datos[i].entry);
		table->attach(*alignment, datos[i].right, datos[i].right + 1, datos[i].top, datos[i].bottom);
	}
}

void VentanaPrincipal::accionEjecutar()
{
	if (timer_.empty()) {
		timer_ = Glib::signal_timeout().connect(
			sigc::mem_fun(*this, &VentanaPrincipal::avanzarSimulacion), 1000);
	}
}

void VentanaPrincipal::accionProxima()
{
	if (timer_.empty()) {
		avanzarSimulacion();
	}
}

void VentanaPrincipal::accionParar()
{
	if (timer_.connected()) {
		timer_.disconnect();
	}
}

void VentanaPrincipal::accionResetear()
{
	reiniciarSimulacion();
}

bool VentanaPrincipal::avanzarSimulacion()
{
	cout << "paso" << endl;
	return true;
}

void VentanaPrincipal::reiniciarSimulacion()
{
	cout << "reiniciar" << endl;
}

int main(int argc, char **argv)
{
	Main kit(argc, argv);
	VentanaPrincipal window;
	Main::run(window);
	return 0;
}
